package es

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/olivere/elastic/v7"
	"github.com/gogf/gf/util/gconv"
)

// 获取结果
func (m *Model) GetResult() (interface{}, error) {
	r, e := m.Search(m.query.size, m.query.from)
	if e != nil {
		return nil, e
	}
	if r.Hits == nil || r.Hits.Hits == nil {
		return nil, errors.New("Hits result not found")
	}
	return gconv.Map(gconv.String(r)), nil
}

// 获取分页列表
func (m *Model) GetList() (result []interface{}, total int64, err error) {
	r, e := m.Search(m.query.size, m.query.from)
	if e != nil {
		return nil, 0, e
	}
	return m.formatResult(r)
}


// 获取第一条数据
func (m *Model) GetFirst() (interface{}, error) {
	r, e := m.Search(m.query.size, m.query.from)
	if e != nil {
		return nil, e
	}
	result, _, err := m.formatResult(r)
	return result[0], err
}

// 结果转化结构体
func (m *Model) Struct(pointer interface{}) error {
	result, err := m.One()
	if err != nil {
		return err
	}
	if err = gconv.Struct(result, pointer); err != nil {
		return err
	}
	return nil
}

// 结果转化结构体
func (m *Model) Structs(pointer interface{}) error {
	result, _, err := m.All()
	if err != nil {
		return err
	}
	if err = gconv.Structs(result, pointer); err != nil {
		return err
	}
	return nil
}

// 请求查询, 指定size与from, 返回原生查询结果
func (m *Model) Search(size int, from int) (*elastic.SearchResult, error) {
	search := m.formatCondition()
	ctx := context.Background()
	return search.Size(size).From(from).Do(ctx)
}

// count
func (m *Model) Count() (int64, error) {
	search := m.formatCondition()
	res, err := search.RestTotalHitsAsInt(true).Do(context.Background())
	if err != nil {
		return 0, err
	}
	return res.TotalHits(), nil
}

// 是否为空
func (m *Model) IsEmpty() (bool, error) {
	r, e := m.Search(m.query.size, m.query.from)
	if e != nil {
		return true, e
	}
	_, total, err := m.formatResult(r)
	if err != nil {
		return true, err
	}
	if total > 0 {
		return false, nil
	}
	return true, nil
}

// 获取query部分的string
func (m *Model) GetRawString() string {
	s, _ := m.getBoolQuery().Source()
	b, _ := json.Marshal(s)
	return string(b)
}

// 解析搜索结果
func (m *Model) formatResult(r *elastic.SearchResult) (result []interface{}, total int64, err error) {
	if r.Hits == nil || r.Hits.Hits == nil {
		return nil, 0, errors.New("Hits result not found")
	}
	var slice []interface{}
	var doc map[string]interface{}
	for _, row := range r.Hits.Hits {
		if row.Source != nil {
			if err := json.Unmarshal(row.Source, &doc); err != nil {
				return nil, 0, err
			}
		}
		doc["_index"] = row.Index
		doc["_type"] = row.Type
		doc["_id"] = row.Id
		doc["_score"] = row.Score
		if m.query.highlight != "" {
			doc["highlight"] = row.Highlight
		}
		slice = append(slice, doc)
		doc = nil
	}
	return slice, r.TotalHits(), nil
}
